import { Prefab, Node } from "cc";
import { UITransform } from "cc";
import { Widget } from "cc";
import { v3 } from "cc";
import { instantiate } from "cc";
import { v2 } from "cc";
import { Enum } from "cc";
import { ScrollView } from "cc";
import { _decorator } from "cc";

const { ccclass, property } = _decorator;
export interface IListAdapter {
    getItemCount(): number;
    onBindView(view: Node, index: number): void;
    getItemType?(index: number): number;
    onBindFatView?(view: Node, index: number): void;
    // onPullDown?(): void;
    // onScrollToBottom?(): void;
}
export interface INode extends Node {
    type?: number;
    index?: number;
    isBindFinish?: boolean;
    // curIndex?: number;
}
const Direction = Enum({
    TOP_TO_BOTTOM: 0,
    BOTTOM_TO_TOP: 1
});
@ccclass
export default class ListView extends ScrollView {
    @property([Prefab])
    private prefabs = <Prefab[]>[];
    @property({ type: Enum(Direction) })
    private direction = Direction.TOP_TO_BOTTOM;
    @property
    private reversedStartY = false;

    // @property
    // pullDownRange = 0;

    private transform: UITransform;
    private contentTransform: UITransform;

    private views: INode[] = [];
    private cacheViews: INode[] = []; //额外缓存的Views
    private _itemsSize = {};
    private lastBindTime = 0;
    private bindInterval = 0;//延迟加载间隔毫秒
    // private hideOutView = false;

    adapter: IListAdapter = {
        getItemType(index) { //type对应prefabs
            return 0;
        },
        getItemCount() {
            return 0;
        },
        onBindView(view, index) {

        },
        onBindFatView(view, index) {

        },
    }

    public setAdapter(adapter: IListAdapter) {
        this.adapter = adapter
        this.refresh()
    }
    public get height() {
        return this.transform.contentSize.height;
    }
    public get width() {
        return this.transform.contentSize.width;
    }
    public get contentHeight() {
        return this.contentTransform.contentSize.height;
    }
    public get contentWidth() {
        return this.contentTransform.contentSize.width;
    }
    protected onLoad(): void {
        // this.addPullDownListenter();
        // this.addScrollToBottomListener();
        this.transform = this.node.getComponent(UITransform);
        this.contentTransform = this.content.getComponent(UITransform);
        if (this.brake < 0.75) {
            this.brake = 0.75;//限速
        }
        // this.hideOutView = true;//位置计算有点问题，暂时先不要用这个功能
        // game.on(game.EVENT_SHOW, this.onGameShow, this);
        this.setDirection();
    }
    public setDirection(direction = this.direction) {
        this.direction = direction;
        this.contentTransform.anchorPoint = v2(0.5, this.direction ? 0 : 1);
        //content禁止有Widget组件
        this.content.getComponent(Widget)?.destroy();
    }
    // private onGameShow() {
    //     this.refresh(false);
    // }

    private refreshSize() {
        this.calContentHeight();
    }
    private saveItemSize(index: number, width: number, height: number) {
        const self = this;
        var flag = false;
        if (!self._itemsSize[index]) {
            self._itemsSize[index] = {
                width: width,
                height: height,
            }
            flag = true;
        } else if (self._itemsSize[index].width != width || self._itemsSize[index].height != height) {
            self._itemsSize[index] = {
                width: width,
                height: height,
            }
            flag = true;
        }
        if (flag) {
            self.refreshSize();
        }
    }
    private getItemType(index: number) {
        if (this.adapter?.getItemType) {
            return this.adapter.getItemType(index);
        }
        return 0;
    }
    private getHeightByIndex(index: number) {
        let type = this.getItemType(index);
        return this._itemsSize[index] ? this._itemsSize[index].height : this.prefabs[type].data.getComponent(UITransform).height;
    }
    // private getWidthByIndex(index: number) {
    //     let type = this.getItemType(index);
    //     return this._itemsSize[index] ? this._itemsSize[index].width : this.prefabs[type].data.width;
    // }
    private getView(type: number, index: number) {
        let len = this.cacheViews.length;
        var view: INode = null;
        for (let i = 0; i < len; i++) {
            if (this.cacheViews[i].type == type) {
                view = this.cacheViews.splice(i, 1)[0];
                view.active = true;
                view.parent = this.content;
                break;
            }
        }
        if (!view) {
            view = this.onCreateView(type);
            this.content.addChild(view);
        }

        // // console.log("getView");
        // const self = this;
        // var view;
        // var pool = self.nodePools[type];
        // if (pool.size() > 0) { // 通过 size 接口判断对象池中是否有空闲的对象
        //     view = pool.get();
        // } else { // 如果没有空闲对象，也就是对象池中备用对象不够时，我们就用 instantiate 重新创建
        //     view = self.onCreateView(type,index);
        // }
        this.lastBindTime = new Date().getTime();
        view.isBindFinish = false;
        // view.curIndex = index;
        return view;
    }
    private onCreateView(type: number) {
        let view = <INode><any>instantiate(this.prefabs[type]);
        view.type = type;
        return view;
    }
    public getViewByIndex(index: number) {
        for (let i = 0; i < this.views.length; i++) {
            const v = this.views[i];
            if (v.index == index) {
                return v;
            }
        }
        return null;
    }
    // 计算View在ScrollView中的位置
    private getPositionInView(view: INode) {
        let worldPos = v3(view.worldPosition);
        let viewPos = this.node.worldPosition;
        return worldPos.subtract(viewPos);
    }
    // 检查是否需要移除或添加View
    private checkeTopAndBottom() {
        const self = this;
        if (self.views.length < 3) {
            return;//当总item不超过3个，不使用这种复用机制
        }
        // var ly = self.content.position.y;
        // if (ly <= self.node.height/2 || ly >= (self.content.height - self.node.height/2)) {
        //     return;
        // }

        let hasChanged = false;
        let viewFirst = self.views[0];
        let viewSecond = self.views[1];
        let p1 = self.getPositionInView(viewFirst);
        let outHeight = self.transform.height / 2 + viewSecond.getComponent(UITransform).height + viewFirst.getComponent(UITransform).height / 2;
        if (self.views.length > 3) {
            if (Math.abs(p1.y) > outHeight) {
                self.removeFirstView();
                viewFirst = null;
                hasChanged = true;
            }
        }

        let viewLast = self.views[self.views.length - 1];
        let viewLast1 = self.views[self.views.length - 2];
        let p2 = self.getPositionInView(viewLast);
        outHeight = self.transform.height / 2 + viewLast1.getComponent(UITransform).height + viewLast.getComponent(UITransform).height / 2;
        if (self.views.length > 3 && Math.abs(p2.y) > outHeight) {
            self.removeLastView();
            viewLast = null;
            hasChanged = true;
        }
        const t2b = this.direction == Direction.TOP_TO_BOTTOM;
        //然后把添加View的逻辑搞进来 应该可以加到上面吧
        if (viewFirst && viewFirst.index != 0) {
            if ((Math.abs(p1.y) < self.transform.height / 2 + viewFirst.getComponent(UITransform).height / 2)
                || (t2b && p1.y < 0)
                || ((!t2b) && p1.y > 0)) {
                self.addFirstView();
                hasChanged = true;
            }
        }
        if (viewLast && viewLast.index != self.adapter?.getItemCount() - 1) {
            if ((Math.abs(p2.y) < self.transform.height / 2 + viewLast.getComponent(UITransform).height / 2)
                || (!t2b && p2.y < 0)
                || (t2b && p2.y > 0)) {
                self.addLastView();
                hasChanged = true;
            }
        }
        // if (viewLast &&
        //     ((Math.abs(p2.y) < self.node.height / 2 + viewLast.height / 2) || (p2.y > 0))
        //     && viewLast.index != self.adapter?.getItemCount() - 1) {
        //     self.addLastView();
        //     hasChanged = true;
        // }
        // if (this.hideOutView && hasChanged) {
        return hasChanged;
    }
    // // 检查所有item 超出屏幕隐藏 在屏幕内 显示
    // private checkOutView() {
    //     // let hideCount = 0;
    //     const len = this.views.length;
    //     for (let i = 0; i < len; i++) {
    //         const view = this.views[i];
    //         let p = this.getPositionInView(view);
    //         if (Math.abs(p.y) > this.transform.height / 2 + view.getComponent(UITransform).height / 2) {
    //             view.active = false
    //         } else {
    //             view.active = true
    //         }
    //     }
    //     // console.log("hideCount:" + hideCount);
    // }
    public refresh(bResetPos = true) {
        if (bResetPos) {
            this.stopAutoScroll()
            if (this.direction) {
                this.scrollToBottom(0);
            } else {
                this.scrollToTop(0);
            }
        }
        let len = this.views.length;
        // const bFirst = len == 0;
        for (let i = 0; i < len; i++) {
            let view = this.views.pop();
            this.cacheViews.push(view);
            view.active = false
            // self.nodePools[view.type].put(view);
        }
        this.refreshSize();
        const halfH = this.height / 2;
        let y = this.direction ? this.content.position.y + halfH : this.content.position.y - halfH;
        console.log("content y = "+y);
        let sumH = 0;
        len = this.adapter?.getItemCount();
        for (let i = 0; i < len; i++) {
            // if (bFirst && i >= 3) {
            //     break;
            // }
            let h = this.getHeightByIndex(i);
            sumH += h;
            if ((!this.direction && (sumH >= y - h / 2)) || (this.direction && (-sumH <= y + h / 2))) {
                // let view = self.views.length==0?self.addBottomView(i,-v + h/2): self.addBottomView();
                let view = this.views.length == 0 ? this.addLastView(i) : this.addLastView();
                let p = this.getPositionInView(view);
                if (this.direction) {
                    if (p.y > (this.height / 2) + view.getComponent(UITransform).height / 2 && i > 2) {
                        break;
                    }
                } else {
                    if (p.y < (-this.height / 2) - view.getComponent(UITransform).height / 2 && i > 2) {
                        break;
                    }
                }
            }
        }
        // this.calContentHeight();
        this.refreshSize();
    }
    private addFirstView() {
        // console.log('addFirstView');
        const bZero = this.views.length == 0;
        const viewFirst = this.views[0];
        const index = bZero ? 0 : viewFirst.index - 1;
        const type = this.getItemType(index);
        const view = this.getView(type, index);
        this.adapter?.onBindView(view, index);
        const transform = view.getComponent(UITransform);
        const halfH = transform.height / 2;
        this.saveItemSize(index, transform.width, transform.height);
        let y = 0;
        if (this.direction) {
            y = bZero ? halfH : viewFirst.position.y - viewFirst.getComponent(UITransform).height / 2 - halfH;
        } else {
            y = bZero ? -halfH : viewFirst.position.y + viewFirst.getComponent(UITransform).height / 2 + halfH;
        }
        view.setPosition(0, y);
        this.views.unshift(view);
        view.index = index;
        this.updateItemsSibling();
    }
    private addLastView(i?: number) {
        // console.log('addLastView', i);
        const bZero = this.views.length == 0;
        const viewLast = this.views[this.views.length - 1];
        const index = i ? i : (bZero ? 0 : viewLast.index + 1);
        const type = this.getItemType(index);
        const view = this.getView(type, index);
        const transform = view.getComponent(UITransform);
        this.adapter?.onBindView(view, index);
        this.saveItemSize(index, transform.width, transform.height);
        let sumHeihgt = 0;
        for (let j = 0; j <= index; j++) sumHeihgt += this.getHeightByIndex(j);
        let y = 0;
        const halfH = transform.height / 2;
        if (i) {
            if (this.direction) {
                y = sumHeihgt - halfH
            } else {
                y = -sumHeihgt + halfH
            }
        } else {
            if (this.direction) {
                y = bZero ? halfH : viewLast.position.y + viewLast.getComponent(UITransform).height / 2 + halfH;
            } else {
                y = bZero ? -halfH : viewLast.position.y - viewLast.getComponent(UITransform).height / 2 - halfH;
            }
        }

        view.setPosition(0, y);
        this.views.push(view);
        view.index = index;
        this.updateItemsSibling();
        return view;
    }
    private removeFirstView() {
        // console.log("removeFirstView");
        let view = this.views.shift();
        this.cacheViews.push(view);
        view.parent = null;
        // view.active = false
        // self.nodePools[view.type].put(view);
        this.updateItemsSibling();
    }
    private removeLastView() {
        // console.log("removeLastView");
        let view = this.views.pop();
        this.cacheViews.push(view);
        view.active = false
        // self.nodePools[view.type].put(view);
        this.updateItemsSibling();
    }
    public updateItemsSibling() {
        for (let i = 0; i < this.views.length; i++) {
            const v = this.views[i];
            v.setSiblingIndex(i);
        }
    }
    // 计算滚动内容的总高度
    private calContentHeight() {
        let count = this.adapter?.getItemCount();
        let contentHeight = 0;
        for (let i = 0; i < count; i++) {
            contentHeight += this.getHeightByIndex(i);
        }
        if (this.reversedStartY) {
            const bool = contentHeight < this.height;
            this.contentTransform.height = contentHeight;
            if (bool) {
                let y = this.height / 2 - contentHeight;
                y = this.direction == Direction.BOTTOM_TO_TOP ? y : -y;
                this.content.setPosition(this.content.position.x, y);
            }
        } else {
            this.contentTransform.height = Math.max(contentHeight, this.height);
        }
        // this.contentTransform.setContentSize(this.contentTransform.contentSize);
        console.log("calContentHeight:"+this.contentTransform.height);
    }
    private lastCheckTime = 0;
    // 延迟加载部分耗性能的View
    private checkBindFatView() {
        const curtime = new Date().getTime();
        if (curtime - this.lastCheckTime < 100) {
            return;
        }
        this.lastCheckTime = curtime;
        if (curtime - this.lastBindTime > this.bindInterval) {
            this.bindFatView();
        }
    }
    private bindFatView() {
        var hasMore = false;
        for (let i = 0; i < this.views.length; i++) {
            const v = this.views[i];
            if (v.isBindFinish) {
                continue;
            }
            if (this.adapter.onBindFatView) {
                this.adapter.onBindFatView(v, v.index);
            }
            v.isBindFinish = true;
            hasMore = i < this.views.length - 1;
            break;
        }
        this.lastBindTime = new Date().getTime();
        return hasMore;
    }

    private updateInterval = 0.0001;//s
    private sumInterval = 0;
    public update(dt: number): void {
        super.update(dt);
        this.sumInterval += dt;
        if (this.sumInterval < this.updateInterval) {
            return;
        }
        this.sumInterval = 0;
        this.checkeTopAndBottom()
        // this.checkBindFatView();
    }
    protected onDestroy(): void {
        for (const nd of this.cacheViews) {
            nd && nd.isValid && nd.destroy();
        }
    }
    // //=======下面是一些辅助功能========
    // //指定index的Item回调一次onBindView
    // refreshItem(index) {
    //     // console.log("refreshItem " + index);
    //     let v = this.getViewByIndex(index);
    //     if (v) {
    //         this.adapter?.onBindView(v, index);
    //         this.updatePosition(index);
    //         // this.saveItemSize(index, v.width, v.height);
    //     }
    // }
    // /**
    //  * 调整位置
    //  * 当一个item onBindView回调完成之后，还需要改变item大小，调此方法
    //  * 例如：onBindFatView里改变了item大小
    //  * 记得之前要updateLayout
    //  */
    // updatePosition(index) {
    //     // console.log("updatePosition "+index);
    //     let v = this.getViewByIndex(index);
    //     if (!v) {
    //         return;
    //     }
    //     let offset = { x: 0, y: 0 };
    //     if (this.horizontal) {
    //         let width = this.getWidthByIndex(index);
    //         offset.x = width - v.width;
    //     } else {
    //         let height = this.getHeightByIndex(index);
    //         offset.y = height - v.height;
    //     }
    //     this.saveItemSize(index, v.width, v.height);
    //     v.x += offset.x / 2;
    //     v.y += offset.y / 2;
    //     for (let i = index + 1; i < this.views.length; i++) {
    //         let view = this.views[i];
    //         view.x += offset.x;
    //         view.y += offset.y;
    //     }
    // }
}
